package com.wg.system.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.wg.common.constant.UserConstants;
import com.wg.common.core.domain.PageQuery;
import com.wg.common.core.domain.TableDataInfo;
import com.wg.common.exception.ServiceException;
import com.wg.common.utils.JsonUtils;
import com.wg.common.utils.RedisUtils;
import com.wg.common.utils.StringUtils;
import com.wg.file.constant.FileConstant;
import com.wg.file.factory.FileFactory;
import com.wg.system.entity.SysFileConfig;
import com.wg.system.mapper.SysFileConfigMapper;
import com.wg.system.service.SysFileConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;

/**
 * 对象存储配置表(SysFileConfig)服务实现类
 *
 * @author wg
 * @date 2022-05-06 11:18:31
 */
@Slf4j
@Service
public class SysFileConfigServiceImpl extends ServiceImpl<SysFileConfigMapper, SysFileConfig> implements SysFileConfigService {

    @Override
    public void init() {
        List<SysFileConfig> list = baseMapper.selectList(new QueryWrapper<>());
        // 加载初始化配置
        for (SysFileConfig config : list) {
            String configKey = config.getConfigKey();
            if ("0".equals(config.getStatus())) {
                RedisUtils.setCacheObject(FileConstant.CACHE_CONFIG_KEY, configKey);
            }
            setConfigCache(true, config);
        }
        // 初始化OSS工厂
        FileFactory.init();
    }

    @Override
    public TableDataInfo<SysFileConfig> queryPageList(SysFileConfig fileConfig, PageQuery pageQuery) {
        LambdaQueryWrapper<SysFileConfig> lqw = new LambdaQueryWrapper<SysFileConfig>()
                .eq(StringUtils.isNotBlank(fileConfig.getConfigKey()), SysFileConfig::getConfigKey, fileConfig.getConfigKey())
                .like(StringUtils.isNotBlank(fileConfig.getBucketName()), SysFileConfig::getBucketName, fileConfig.getBucketName())
                .eq(StringUtils.isNotBlank(fileConfig.getStatus()), SysFileConfig::getStatus, fileConfig.getStatus());
        Page<SysFileConfig> page = baseMapper.selectPage(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }

    @Override
    public boolean insert(SysFileConfig fileConfig) {
        validEntityBeforeSave(fileConfig);
        return setConfigCache(baseMapper.insert(fileConfig) > 0, fileConfig);
    }

    @Override
    public Boolean update(SysFileConfig fileConfig) {
        validEntityBeforeSave(fileConfig);
        LambdaUpdateWrapper<SysFileConfig> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(StringUtils.isBlank(fileConfig.getPrefix()), SysFileConfig::getPrefix, "");
        wrapper.set(StringUtils.isBlank(fileConfig.getRegion()), SysFileConfig::getRegion, "");
        wrapper.set(StringUtils.isBlank(fileConfig.getExt1()), SysFileConfig::getExt1, "");
        wrapper.eq(SysFileConfig::getId, fileConfig.getId());
        return setConfigCache(baseMapper.update(fileConfig, wrapper) > 0, fileConfig);
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            if (CollUtil.containsAny(ids, FileConstant.SYSTEM_DATA_IDS)) {
                throw new ServiceException("系统内置, 不可删除!");
            }
        }
        List<SysFileConfig> list = Lists.newArrayList();
        for (Long configId : ids) {
            SysFileConfig config = baseMapper.selectById(configId);
            list.add(config);
        }
        boolean flag = baseMapper.deleteBatchIds(ids) > 0;
        if (flag) {
            list.forEach(sysOssConfig -> {
                RedisUtils.deleteObject(FileConstant.SYS_FILE_KEY + sysOssConfig.getConfigKey());
            });
        }
        return flag;
    }

    /**
     * 启用禁用状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateFileConfigStatus(SysFileConfig fileConfig) {
        int row = baseMapper.update(null, new LambdaUpdateWrapper<SysFileConfig>()
                .set(SysFileConfig::getStatus, "1"));
        row += baseMapper.updateById(fileConfig);
        if (row > 0) {
            RedisUtils.setCacheObject(FileConstant.CACHE_CONFIG_KEY, fileConfig.getConfigKey());
        }
        return row;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysFileConfig fileConfig) {
        if (StringUtils.isNotEmpty(fileConfig.getConfigKey())
                && UserConstants.NOT_UNIQUE.equals(checkConfigKeyUnique(fileConfig))) {
            throw new ServiceException("操作配置'" + fileConfig.getConfigKey() + "'失败, 配置key已存在!");
        }
    }

    /**
     * 如果操作成功 则更新缓存
     *
     * @param flag   操作状态
     * @param config 配置
     * @return 返回操作状态
     */
    private boolean setConfigCache(boolean flag, SysFileConfig config) {
        if (flag) {
            RedisUtils.setCacheObject(FileConstant.SYS_FILE_KEY + config.getConfigKey(), JsonUtils.toJsonString(config));
            RedisUtils.publish(FileConstant.CACHE_CONFIG_KEY, config.getConfigKey(), msg -> {
                log.info("发布刷新 file 配置 => " + msg);
            });
        }
        return flag;
    }

    /**
     * 判断configKey是否唯一
     */
    private String checkConfigKeyUnique(SysFileConfig fileConfig) {
        long configId = ObjectUtil.isNull(fileConfig.getId()) ? -1L : fileConfig.getId();
        SysFileConfig info = baseMapper.selectOne(new LambdaQueryWrapper<SysFileConfig>()
                .select(SysFileConfig::getId, SysFileConfig::getConfigKey)
                .eq(SysFileConfig::getConfigKey, fileConfig.getConfigKey()));
        if (ObjectUtil.isNotNull(info) && info.getId() != configId) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }
}

